home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 4
/
Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso
/
Pearls
/
libs
/
bgui
/
Demos
/
multicol.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-26
|
35KB
|
795 lines
;/*
dcc MultiCol.c -proto -mi -ms -mRR -lbgui
quit
*/
/*
* MULTICOL.C
*
* (C) Copyright 1995 Jaba Development.
* (C) Copyright 1995 Jan van den Baard.
* All Rights Reserved.
*/
#include "democode.h"
#include <dos/exall.h>
#include <utility/hooks.h>
#include <clib/macros.h>
#include <strings.h>
#include <stdio.h>
/*
** This is the data were going to add
** to the listview object. It is a simple
** structure in which the file-information
** is stored. This data is created in the
** LISTV_Resource hook from a pointer
** to a ExAllData structure.
**/
typedef struct {
UBYTE fi_FileName[ 108 ];
UBYTE fi_Size[ 11 ];
UBYTE fi_Date[ 32 ];
BOOL fi_IsDir;
} FILEINFO;
/*
** The LISTV_Resource hook is used to create
** the FILEINFO structures from a struct ExAllData
** at create time. At delete time the FILEINFO
** structure is simply deallocated.
**/
SAVEDS ASM APTR ResourceHookFunc( REG(a0) struct Hook *hook, REG(a2) Object *obj, REG(a1) struct lvResource *lvr )
{
struct ExAllData *ead;
FILEINFO *fi;
struct DateTime dt;
APTR return_code = NULL;
/*
** What must we do?
**/
switch ( lvr->lvr_Command ) {
case LVRC_MAKE:
/*
** Create a FILEINFO structure.
** BGUI has passed us a pointer to a
** ExAllData structure. Here we
** convert it to a FILEINFO structure
** which, eventually, get's added to
** the listview.
**/
if ( fi = ( FILEINFO * )AllocVec( sizeof( FILEINFO ), MEMF_PUBLIC )) {
/*
** Pick up the ExAllData.
**/
ead = ( struct ExAllData * )lvr->lvr_Entry;
/*
** Copy the name.
**/
strcpy( &fi->fi_FileName[ 0 ], ead->ed_Name );
/*
** Format the size text. We can do all sorts of
** fancy stuff here like using the locale.library
** formatting stuff but hey, it's just a demo ;)
**/
if ( ead->ed_Type < 0 ) {
fi->fi_IsDir = FALSE;
sprintf( &fi->fi_Size[ 0 ], "%ld", ead->ed_Size );
} else {
fi->fi_IsDir = TRUE;
strcpy( &fi->fi_Size[ 0 ], "(dir)" );
}
/*
** Convert the date to a string.
**/
dt.dat_Stamp = *(( struct DateStamp * )&ead->ed_Days );
dt.dat_Format = FORMAT_CDN;
dt.dat_Flags = DTF_SUBST | DTF_FUTURE;
dt.dat_StrDay = NULL;
dt.dat_StrDate = &fi->fi_Date[ 0 ];
dt.dat_StrTime = NULL;
/*
** Format date.
**/
DateToStr( &dt );
/*
** Return a pointer to the created
** FILEINFO structure.
**/
return_code = ( APTR )fi;
}
break;
case LVRC_KILL:
/*
** Simply deallocate the FILEINFO
** structure which has been created with
** LVRC_MAKE above.
**/
FreeVec( lvr->lvr_Entry );
break;
}
/*
** Pointer to FILEINFO or NULL.
**/
return( return_code );
}
/*
** The listview will have three columns.
**
** Name Size Date
**
** The following globals will contain the maximum
** width of each of these columns.
**/
UWORD MaxName, MaxSize, MaxDate;
/*
** This global stores the total width of the
** listview drawing area.
**/
UWORD TotalWidth = 0;
/*
** This boolean determines wether the hook must
** re-compute the column sizes.
**/
BOOL ReCompCols = TRUE;
/*
** We use 16 pixels as a minimum inner-column spacing.
**/
#define INNER_SPACE 16
/*
** This routine re-computes the minimum column
** sizes when necessary.
**/
VOID ReComputeColumns( struct RastPort *rp, Object *obj, UWORD list_width )
{
FILEINFO *fi;
UWORD tmp, total;
/*
** A re-computation is necessary when:
**
** 1) The ReCompCols flag is TRUE.
** 2) The with of the listview has changed.
**/
if ( ReCompCols || ( TotalWidth != list_width )) {
/*
** Our listview also has a title entry.
** Here we compute the default column
** sizes accoording to this title.
**/
MaxName = TextLength( rp, "Name:", 6 ) + INNER_SPACE;
MaxSize = TextLength( rp, "Size:", 6 ) + INNER_SPACE;
MaxDate = TextLength( rp, "Date:", 6 );
/*
** Now we loop through the entries to find
** out the largest width of the three columns.
**/
if ( fi = ( FILEINFO * )FirstEntry( obj )) {
/*
** Loop until all are done.
**/
while ( fi ) {
/*
** Compute width of the Name: column
** for this entry.
**/
tmp = TextLength( rp, &fi->fi_FileName[ 0 ], strlen( &fi->fi_FileName[ 0 ] )) + INNER_SPACE;
/*
** Is it bigger than the last one?
** If so store it.
**/
if ( tmp > MaxName ) MaxName = tmp;
/*
** Compute width of the Size: column
** for this entry.
**/
tmp = TextLength( rp, &fi->fi_Size[ 0 ], strlen( &fi->fi_Size[ 0 ] )) + INNER_SPACE;
/*
** Is it bigger than the last one?
** If so store it.
**/
if ( tmp > MaxSize ) MaxSize = tmp;
/*
** Compute width of the Date: column
** for this entry.
**/
tmp = TextLength( rp, &fi->fi_Date[ 0 ], strlen( &fi->fi_Date[ 0 ] ));
/*
** Is it bigger than the last one?
** If so store it.
**/
if ( tmp > MaxDate ) MaxDate = tmp;
/*
** Pick up the next entry.
**/
fi = ( FILEINFO * )NextEntry( obj, fi );
}
}
/*
** Compute the total columns width.
**/
total = MaxName + MaxSize + MaxDate;
/*
** If there's room left over we
** distribute it between the columns so
** we get a nice even spacing between
** them.
**/
if ( list_width > total ) {
MaxName += ( list_width - total ) >> 1;
MaxSize += ( list_width - total ) >> 1;
}
/*
** All done. Set the re-compute flag to
** FALSE and store the list width.
**/
ReCompCols = FALSE;
TotalWidth = list_width;
}
}
/*
** The default DrawInfo pens. Just in case we don't
** get them from the system.
**/
UWORD DefDriPens[] = {
0, 1, 1, 2, 1, 3, 1, 0, 2, 1, 2, 1 };
/*
** Listview rendering hook. Here's where the magic starts ;)
**/
SAVEDS ASM UBYTE *DisplayHookFunc( REG(a0) struct Hook *hook, REG(a2) Object *obj, REG(a1) struct lvRender *lvr )
{
struct TextExtent te;
UBYTE *str;
FILEINFO *fi = ( FILEINFO * )lvr->lvr_Entry;
UWORD *pens, numc, w, l, cw, h;
/*
** Pick up the DrawInfo pen array.
**/
pens = lvr->lvr_DrawInfo ? lvr->lvr_DrawInfo->dri_Pens : DefDriPens;
/*
** Pick up the width of the list.
**/
w = lvr->lvr_Bounds.MaxX - lvr->lvr_Bounds.MinX + 1;
/*
** Pick up the list left-edge;
**/
l = lvr->lvr_Bounds.MinX;
/*
** Pick up the height of the entry.
**/
h = lvr->lvr_Bounds.MaxY - lvr->lvr_Bounds.MinY + 1;
/*
** First we render the background.
**/
SetAPen( lvr->lvr_RPort, lvr->lvr_State == LVRS_SELECTED ? pens[ FILLPEN ] : pens[ BACKGROUNDPEN ] );
SetDrMd( lvr->lvr_RPort, JAM1 );
RectFill( lvr->lvr_RPort, lvr->lvr_Bounds.MinX,
lvr->lvr_Bounds.MinY,
lvr->lvr_Bounds.MaxX,
lvr->lvr_Bounds.MaxY );
/*
** When we are passed a NULL entry pointer
** we are presumed to render the title. If your
** listview does not have a title simply
** recompute the columns and return NULL.
** We have a title so here we go.
**/
if ( ! fi ) {
/*
** Recompute the column sizes. The routine
** itself will decide if it's necessary.
**/
ReComputeColumns( lvr->lvr_RPort, obj, w );
/*
** Set the pen for the title-entry.
**/
SetAPen( lvr->lvr_RPort, pens[ FILLPEN ] );
} else {
/*
** Set the pen for a non-title entry. Ofcourse
** we can (should?) differenciate between normal and
** selected here but I wont ;)
**/
if ( fi->fi_IsDir ) SetAPen( lvr->lvr_RPort, pens[ HIGHLIGHTTEXTPEN ] );
else SetAPen( lvr->lvr_RPort, pens[ TEXTPEN ] );
}
/*
** Obtain Name: column width. We check it against the
** total list width so we do not go outside the
** given area.
**/
cw = MIN( MaxName, w );
/*
** Pick up the name string or, when this
** is a title call, the string "Name:".
**/
str = fi ? &fi->fi_FileName[ 0 ] : ( UBYTE * )"Name:";
/*
** Compute the number of character we
** can render.
**/
numc = TextFit( lvr->lvr_RPort, str, strlen( str ), &te, NULL, 0, cw, h );
/*
** If the number of characters is
** 0 we can stop right here and now.
**/
if ( ! numc ) return( NULL );
/*
** Move to the correct position
** and render the text.
**/
Move( lvr->lvr_RPort, l, lvr->lvr_Bounds.MinY + lvr->lvr_RPort->TxBaseline );
Text( lvr->lvr_RPort, str, numc );
/*
** Adjust the left-edge and width to
** get past the Name: column.
**/
l += cw;
w = MAX(( WORD )( w - cw ), 0 );
/*
** Obtain Size: column width. We check it against the
** total list width so we do not go outside the
** given area.
**/
cw = MIN( MaxSize, w );
/*
** Pick up the size string or, when this
** is a title call, the string "Size:".
**/
str = fi ? &fi->fi_Size[ 0 ] : ( UBYTE * )"Size:";
/*
** Compute the number of character we
** can render.
**/
numc = TextFit( lvr->lvr_RPort, str, strlen( str ), &te, NULL, 0, cw, h );
/*
** If the number of characters is
** 0 we can stop right here and now.
**/
if ( ! numc ) return( NULL );
/*
** Move to the correct position
** and render the text.
**/
Move( lvr->lvr_RPort, l, lvr->lvr_Bounds.MinY + lvr->lvr_RPort->TxBaseline );
Text( lvr->lvr_RPort, str, numc );
/*
** Adjust the left-edge and width to
** get past the Size: column.
**/
l += cw;
w = MAX(( WORD )( w - cw ), 0 );
/*
** Obtain Date column width. We check it against the
** total list width so we do not go outside the
** given area.
**/
cw = MIN( MaxDate, w );
/*
** Pick up the date string or, when this
** is a title call, the string "Date:".
**/
str = fi ? &fi->fi_Date[ 0 ] : ( UBYTE * )"Date:";
/*
** Compute the number of character we
** can render.
**/
numc = TextFit( lvr->lvr_RPort, str, strlen( str ), &te, NULL, 0, cw, h );
/*
** If the number of characters is
** 0 we can stop right here and now.
**/
if ( ! numc ) return( NULL );
/*
** Move to the correct position
** and render the text.
**/
Move( lvr->lvr_RPort, l, lvr->lvr_Bounds.MinY + lvr->lvr_RPort->TxBaseline );
Text( lvr->lvr_RPort, str, numc );
/*
** Return NULL. This is important. If we return a non-NULL
** value the listview class will think it is a pointer to
** the text to render and try to render it.
**/
return( NULL );
}
/*
** The comparrison hook. We do a simple name, dir/file
** comparrison here.
**/
SAVEDS ASM LONG CompareHookFunc( REG(a0) struct Hook *hook, REG(a2) Object *obj, REG(a1) struct lvCompare *lvc )
{
FILEINFO *a = ( FILEINFO * )lvc->lvc_EntryA;
FILEINFO *b = ( FILEINFO * )lvc->lvc_EntryB;
/*
** First we do a type comparrison to get the
** directories at the top of the list.
**/
if ( a->fi_IsDir && ! b->fi_IsDir ) return( -1L );
else if ( ! a->fi_IsDir && b->fi_IsDir ) return( 1L );
/*
** Otherwise we do a simple, case insensitive,
** name string comparrison.
**/
return( stricmp( &a->fi_FileName[ 0 ], &b->fi_FileName[ 0 ] ));
}
/*
** A IDCMP hook for the window which allows us
** to control the listview from the keyboard.
**/
SAVEDS ASM VOID ScrollHookFunc( REG(a0) struct Hook *hook, REG(a2) Object *obj, REG(a1) struct IntuiMessage *msg )
{
struct Window *window;
Object *lv_obj = ( Object * )hook->h_Data;
/*
** Obtain window pointer.
**/
GetAttr( WINDOW_Window, obj, ( ULONG * )&window );
/*
** What key is pressed?
**/
switch ( msg->Code ) {
case 0x4C:
/*
** UP - Move entry up.
** SHIFT + UP - Move page up.
** CTRL + UP - Move to the top.
**/
if ( msg->Qualifier & ( IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT ))
SetGadgetAttrs(( struct Gadget * )lv_obj, window, NULL, LISTV_Select, LISTV_Select_Page_Up, TAG_END );
else if ( msg->Qualifier & IEQUALIFIER_CONTROL )
SetGadgetAttrs(( struct Gadget * )lv_obj, window, NULL, LISTV_Select, LISTV_Select_First, TAG_END );
else
SetGadgetAttrs(( struct Gadget * )lv_obj, window, NULL, LISTV_Select, LISTV_Select_Previous, TAG_END );
break;
case 0x4D:
/*
** DOWN - Move entry down.
** SHIFT + DOWN - Move page down.
** CTRL + DOWN - Move to the end.
**/
if ( msg->Qualifier & ( IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT ))
SetGadgetAttrs(( struct Gadget * )lv_obj, window, NULL, LISTV_Select, LISTV_Select_Page_Down, TAG_END );
else if ( msg->Qualifier & IEQUALIFIER_CONTROL )
SetGadgetAttrs(( struct Gadget * )lv_obj, window, NULL, LISTV_Select, LISTV_Select_Last, TAG_END );
else
SetGadgetAttrs(( struct Gadget * )lv_obj, window, NULL, LISTV_Select, LISTV_Select_Next, TAG_END );
break;
case 0x43:
case 0x44:
/*
** RETURN or ENTER - Report the listview ID to the event handler.
**/
DoMethod( obj, WM_REPORT_ID, (( struct Gadget * )lv_obj )->GadgetID, 0L );
break;
}
}
/*
** The hook structures as added to the
** listview object and window object.
**
** If your compiler complaints about the
** HOOKFUNC typedef uncomment the below line.
**/
/* typedef ULONG (*HOOKFUNC)(); */
struct Hook ResourceHook = { NULL, NULL, (HOOKFUNC)ResourceHookFunc, NULL, NULL };
struct Hook DisplayHook = { NULL, NULL, (HOOKFUNC)DisplayHookFunc, NULL, NULL };
struct Hook CompareHook = { NULL, NULL, (HOOKFUNC)CompareHookFunc, NULL, NULL };
struct Hook ScrollHook = { NULL, NULL, (HOOKFUNC)ScrollHookFunc, NULL, NULL };
/*
** Scan the directory "name".
**/
VOID ScanDirectory( UBYTE *name, Object *obj )
{
struct ExAllControl *eac;
struct ExAllData *ead, *tmp;
struct FileInfoBlock *fib;
BPTR lock;
BOOL ismore;
/*
** We need to recompute the columns.
**/
ReCompCols = TRUE;
/*
** Get a lock to the directory.
**/
if ( lock = Lock( name, ACCESS_READ )) {
/*
** Allocate a FileInfoBlock structure.
**/
if ( fib = ( struct FileInfoBlock * )AllocDosObject( DOS_FIB, NULL )) {
/*
** Examine the lock.
**/
if ( Examine( lock, fib )) {
/*
** Is this a directory?
**/
if ( fib->fib_DirEntryType > 0 ) {
/*
** Allocate ExAll() control structure.
**/
if ( eac = ( struct ExAllControl * )AllocDosObject( DOS_EXALLCONTROL, NULL )) {
/*
** Set key to NULL.
**/
eac->eac_LastKey = NULL;
/*
** Allocate ExAll() buffer.
**/
if ( ead = ( struct ExAllData * )AllocVec( 10 * sizeof( struct ExAllData ), MEMF_PUBLIC )) {
/*
** Read directory.
**/
do {
/*
** Fill buffer.
**/
ismore = ExAll( lock, ead, 10 * sizeof( struct ExAllData ), ED_DATE, eac );
/*
** Errors? Done?
**/
if (( ! ismore ) && ( IoErr() != ERROR_NO_MORE_ENTRIES ))
break;
/*
** Entries read?
**/
if ( ! eac->eac_Entries )
continue;
/*
** Pick up data pointer.
**/
tmp = ead;
/*
** Add the entries.
**/
do {
AddEntry( NULL, obj, tmp, LVAP_SORTED );
/*
** Next...
**/
tmp = tmp->ed_Next;
} while ( tmp );
} while ( ismore );
/*
** Deallocate ExAll() buffer.
**/
FreeVec( ead );
}
/*
** Deallocate ExAll() control structure.
**/
FreeDosObject( DOS_EXALLCONTROL, eac );
}
}
}
/*
** Deallocate FileInfoBlock structure.
**/
FreeDosObject( DOS_FIB, fib );
}
/*
** Release lock.
**/
UnLock( lock );
}
}
/*
** And were off...
**/
#define ID_QUIT 1
#define ID_LIST 2
#define ID_NEWDIR 3
VOID StartDemo( void )
{
struct RDArgs *ra;
struct Window *win;
Object *WO_DirWin, *GO_DirList, *GO_Quit, *GO_NewDir;
FILEINFO *fi;
ULONG dname = 0L, signal, rc;
UBYTE name[ 512 ], *ptr;
BOOL running = TRUE;
/*
** Parse command line?
**/
if ( ra = ReadArgs( "NAME", &dname, NULL )) {
/*
** Copy the name into the buffer.
**/
if ( dname ) strcpy( name, ( UBYTE * )dname );
else name[ 0 ] = 0;
/*
** Create the listview object.
**/
GO_DirList = ListviewObject,
LISTV_ResourceHook, &ResourceHook,
LISTV_DisplayHook, &DisplayHook,
LISTV_TitleHook, &DisplayHook,
LISTV_CompareHook, &CompareHook,
GA_ID, ID_LIST,
EndObject;
/*
** Put it in the IDCMP hook.
**/
ScrollHook.h_Data = ( APTR )GO_DirList;
/*
** Create the window.
**/
WO_DirWin = WindowObject,
WINDOW_Title, "MultiCol",
WINDOW_RMBTrap, TRUE,
WINDOW_ScaleWidth, 50,
WINDOW_ScaleHeight, 30,
WINDOW_AutoAspect, TRUE,
WINDOW_SmartRefresh, TRUE,
WINDOW_IDCMPHookBits, IDCMP_RAWKEY,
WINDOW_IDCMPHook, &ScrollHook,
WINDOW_MasterGroup,
VGroupObject, HOffset( 4 ), VOffset( 4 ), Spacing( 4 ), GROUP_BackFill, SHINE_RASTER,
StartMember,
VGroupObject,
StartMember, GO_DirList, EndMember,
StartMember,
GO_NewDir = KeyString( NULL, name, 512, ID_NEWDIR ), FixMinHeight,
EndMember,
EndObject,
EndMember,
StartMember,
HGroupObject,
VarSpace( DEFAULT_WEIGHT ),
StartMember, GO_Quit = KeyButton( "_Quit", ID_QUIT ), EndMember,
VarSpace( DEFAULT_WEIGHT ),
EndObject, FixMinHeight,
EndMember,
EndObject,
EndObject;
/*
** Window created OK?
**/
if ( WO_DirWin ) {
/*
** Add gadget key.
**/
if ( GadgetKey( WO_DirWin, GO_Quit, "q" )) {
/*
** Open the window.
**/
if ( win = WindowOpen( WO_DirWin )) {
/*
** Obtain signal mask.
**/
GetAttr( WINDOW_SigMask, WO_DirWin, &signal );
/*
** Read in the directory.
**/
WindowBusy( WO_DirWin );
ScanDirectory( name, GO_DirList );
WindowReady( WO_DirWin );
/*
** Refresh the list.
**/
RefreshList( win, GO_DirList );
/*
** Poll messages...
**/
do {
Wait( signal );
while (( rc = HandleEvent( WO_DirWin )) != WMHI_NOMORE ) {
switch ( rc ) {
case ID_QUIT:
case WMHI_CLOSEWINDOW:
running = FALSE;
break;
case ID_LIST:
/*
** Get selected entry.
**/
if ( fi = ( FILEINFO * )FirstSelected( GO_DirList )) {
/*
** Is the entry a directory?
**/
if ( fi->fi_IsDir ) {
/*
** AddPart() the name to the buffer.
**/
AddPart( name, &fi->fi_FileName[ 0 ], 512 );
/*
** Refresh the string gadget.
**/
SetGadgetAttrs(( struct Gadget * )GO_NewDir, win, NULL, STRINGA_TextVal, name, TAG_END );
/*
** Re-read the list.
**/
refreshDir:
WindowBusy( WO_DirWin );
ClearList( win, GO_DirList );
ScanDirectory( name, GO_DirList );
RefreshList( win, GO_DirList );
WindowReady( WO_DirWin );
}
}
break;
case ID_NEWDIR:
/*
** Copy the new name to the buffer.
**/
GetAttr( STRINGA_TextVal, GO_NewDir, ( ULONG * )&ptr );
strcpy( name, ptr );
goto refreshDir;
}
}
} while ( running );
}
}
/*
** Kill the object.
**/
DisposeObject( WO_DirWin );
}
/*
** Delete the ReadArgs structure.
**/
FreeArgs( ra );
}
}